﻿using Newtonsoft.Json;
using SixLabors.Fonts;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Drawing.Processing;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using Yolov5Net.Scorer;
using Yolov5Net.Scorer.Models;
using Font = SixLabors.Fonts.Font;

namespace YoloConsole
{
    internal class Program
    {
        /// <summary>
        /// 字体所在路径
        /// </summary>
        private readonly static string fontPath = "C:/Windows/Fonts/Arial.ttf";

        /// <summary>
        /// 图片保存位置
        /// </summary>
        private static string imgPath = AppContext.BaseDirectory + "\\Img\\";  // 图片保存位置

        /// <summary>
        /// 模型
        /// </summary>
        private static string modelPath = AppContext.BaseDirectory + "\\yolov5s.onnx";  // 模型

        static void Main(string[] args)
        {
            try
            {
                #region 校验参数
                string toBeTestedImgPathStr = AppContext.BaseDirectory + "\\test.jpg";
                if (args.Length > 0)
                {
                    toBeTestedImgPathStr = args[0];
                }

                if (string.IsNullOrEmpty(toBeTestedImgPathStr))
                {
                    Console.WriteLine("检测失败！要识别的图片不可为空！");
                    return;
                }
                if (!File.Exists(toBeTestedImgPathStr))
                {
                    Console.WriteLine("检测失败！要识别的图片路径无效！");
                    return;
                }
                string toBeTestedImgFullNameStr = Path.GetFileName(toBeTestedImgPathStr);  // 图片文件名称_全称

                string toBeTestedImgNewNameStr = string.Empty;
                if (toBeTestedImgFullNameStr.Contains("."))
                {
                    string[] toBeTestedImgFullNameStrs = toBeTestedImgFullNameStr.Split(".");
                    string toBeTestedImgNamePostfixStr = toBeTestedImgFullNameStrs[toBeTestedImgFullNameStrs.Length - 1];  // 图片文件名称
                    string toBeTestedImgNameStr = toBeTestedImgFullNameStr.Replace(toBeTestedImgNamePostfixStr, "");  // 图片文件后缀类型

                    toBeTestedImgNewNameStr = string.Concat(imgPath, toBeTestedImgNameStr, DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff"), ".", toBeTestedImgNamePostfixStr);
                }
                else
                {
                    toBeTestedImgNewNameStr = string.Concat(imgPath, toBeTestedImgFullNameStr);
                }
                #endregion 校验参数

                Font font = new Font(new FontCollection().Add(fontPath), 16);

                using Image<Rgba32> image = SixLabors.ImageSharp.Image.Load<Rgba32>(toBeTestedImgPathStr);  // 载入图片
                //using Image<Rgba32> image = (Image<Rgba32>)ImageSharpImageConvertHelper.BitmapConvertToImage(sourceImg_Bitmap);
                {
                    using YoloScorer<YoloCocoP5Model> scorer = new YoloScorer<YoloCocoP5Model>(modelPath);  // 选择模型
                    {
                        List<YoloPrediction> predictions = scorer.Predict(image);  // 预测

                        // 保存人体位置信息
                        List<BodyInfo> bodyInfos = new List<BodyInfo>();

                        // 标注图片
                        foreach (YoloPrediction prediction in predictions)
                        {
                            if (prediction.Label.Name == "person")  // prediction.Label.Id == "1"
                            {
                                double score = Math.Round(prediction.Score, 2);                               // 概率（保留两位小数）
                                var (x, y) = (prediction.Rectangle.Left - 3, prediction.Rectangle.Top - 23);  // 标注信息的位置信息

                                // 标说明
                                image.Mutate(a => a.DrawText($"{prediction.Label.Name} ({score})",
                                                font, prediction.Label.Color, new PointF(x, y)));

                                // 框位置
                                image.Mutate(a => a.DrawPolygon(prediction.Label.Color, 1,
                                    new PointF(prediction.Rectangle.Left, prediction.Rectangle.Top),
                                    new PointF(prediction.Rectangle.Right, prediction.Rectangle.Top),
                                    new PointF(prediction.Rectangle.Right, prediction.Rectangle.Bottom),
                                    new PointF(prediction.Rectangle.Left, prediction.Rectangle.Bottom)
                                    ));

                                bodyInfos.Add(new BodyInfo((int)prediction.Rectangle.Left, (int)prediction.Rectangle.Top, (int)prediction.Rectangle.Right, (int)prediction.Rectangle.Bottom, score));
                            }
                        }

                        // 保存
                        image.SaveAsync(toBeTestedImgNewNameStr);
                        //MessageBox.Show("识别成功！保存地址：" + toBeTestedImgNewNameStr, "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);

                        // 返回人体的位置与宽高
                        string resultStr = JsonConvert.SerializeObject(bodyInfos);

                        Console.WriteLine(resultStr);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("检测失败！" + ex.Message);
            }
        }
    }

    /// <summary>
    /// 人体信息
    /// </summary>
    public class BodyInfo
    {
        public int Left { get; set; } = 0;
        public int Top { get; set; } = 0;
        public int Right { get; set; } = 0;
        public int Bottom { get; set; } = 0;

        /// <summary>
        /// 概率
        /// </summary>
        public double Score { get; set; } = 0;

        public BodyInfo(int left, int top, int right, int bottom, double score)
        {
            Left = left;
            Top = top;
            Right = right;
            Bottom = bottom;
            Score = score;
        }
    }
}